﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.IO;
using System.Windows.Forms;

namespace MigrationTool
{
    /// <summary>
    /// OUKLOOKオブジェクトクラス
    /// </summary>
    public class OutlookOperation : IDisposable
    {
        #region インスタンス
        CommonModule clsMod = new CommonModule();
        #endregion

        #region アクセサ
        private Outlook.Application OutLookApplication{get;set;}
        private Outlook.NameSpace OutLookSession { get; set; }
        #endregion

        #region メソッド
        /// <summary>
        /// OUTLOOK開始
        /// </summary>
        public OutlookOperation()
        {
            Open(string.Empty, string.Empty);
        }

        /// <summary>
        /// OUTLOOK開始
        /// </summary>
        /// <param name="profileName">プロファイル名</param>
        public OutlookOperation(string profileName)
        {
            Open(profileName, string.Empty);
        }

        /// <summary>
        /// OUTLOOK開始
        /// </summary>
        /// <param name="profileName">プロファイル名</param>
        /// <param name="profilePassword">パスワード</param>
        public OutlookOperation(string profileName,string profilePassword)
        {
            Open(profileName, profilePassword);
        }

        /// <summary>
        /// MAPI開始
        /// </summary>
        /// <param name="profileName">プロファイル名</param>
        /// <param name="profilePassword">パスワード</param>
        public void Open(string profileName, string profilePassword)
        {
            OutLookApplication = new Outlook.Application();

            if (!string.IsNullOrEmpty(profileName))
            {
                OutLookSession = OutLookApplication.GetNamespace(ApplicationConst.MAPI).Session;
                OutLookSession.Logon(profileName, profilePassword, Type.Missing, Type.Missing);
            }
        }

        /// <summary>
        /// OUTLOOK終了
        /// </summary>
        public void Close()
        {
            if (OutLookSession != null)
            {
                OutLookSession.Logoff();
                Marshal.ReleaseComObject(OutLookSession);
            }
            if (OutLookApplication != null)
            {
                (OutLookApplication as Outlook._Application).Quit();
                Marshal.ReleaseComObject(OutLookApplication);
            }
            GC.Collect();
        }

        /// <summary>
        /// 解放
        /// </summary>
        public void Dispose()
        {
            Close();
        }

        /// <summary>
        /// メールボックスデータを出力
        /// </summary>
        /// <param name="strFilePath">生成されるPSTファイルパス</param>
        /// <param name="targetAlias">生成されるPSTのユーザーのエイリアス</param>
        /// <param name="TempFolder">PSTファイルの生成フォルダー名</param>
        /// <param name="txtLog">ログ出力指定テキストボックス</param>
        /// <param name="strProfileName">プロファイル名</param>
        /// <param name="time">待機時間</param>
        public bool ExportMailboxPstFile(string strFilePath, string targetAlias,string TempFolder,System.Windows.Forms.TextBox txtLog,string strProfileName,int time)
        {
            bool bolRet = true;
            foreach (Outlook.MAPIFolder folder in OutLookSession.Folders)
            {
                //対象のエイリアスのみ処理を行う
                if (folder.Name == targetAlias)
                {
                    //新規ストアを作成
                    OutLookSession.AddStoreEx(strFilePath, Outlook.OlStoreType.olStoreUnicode);
                    foreach (Outlook.Store store in OutLookSession.Stores)
                    {
                        if (store.FilePath == strFilePath)
                        {
                            //対象メールアドレスのルートフォルダ取得
                            Outlook.MAPIFolder newRootFolder = store.GetRootFolder();
                            //ルートフォルダの名前変更
                            newRootFolder.Name = targetAlias;
                            //移行用サブフォルダの追加
                            newRootFolder.Folders.Add(TempFolder);
                            //サブフォルダを新しいストアのルートフォルダにコピー
                            //（中のメールアイテムも一緒にコピーされる）
                            foreach (Outlook.MAPIFolder migFolder in newRootFolder.Folders)
                            {
                                int intCheckCount = 0;
                                //移行専用フォルダにのみコピー
                                if (migFolder.Name == TempFolder)
                                {
                                    string SourceFilePath = string.Format(ApplicationConst.OUTLOOK_DEFAULT_PATH, Environment.UserName.ToString(), Environment.UserDomainName.ToString(), targetAlias, strProfileName);
                                    //サブフォルダを新しいストアのルートフォルダにコピー
                                    //（中のメールアイテムも一緒にコピーされる）
                                    foreach (Outlook.MAPIFolder subFolder in folder.Folders)
                                    {
                                        try
                                        {
                                            Outlook.Folder copyFolder = subFolder.CopyTo(migFolder) as Outlook.Folder;
                                            bool bolCheckItemCount = false;
                                            clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_START, LogConst.LOG_COMPARE + subFolder.Name + LogConst.LOG_ITEMCOUNT));
                                            while (!bolCheckItemCount && intCheckCount <= 100)
                                            {
                                                Thread.Sleep(100);
                                                intCheckCount++;
                                                if (subFolder.Items.Count == copyFolder.Items.Count)
                                                {
                                                    bolCheckItemCount = true;
                                                    intCheckCount = 0;
                                                }
                                            }
                                            if (!bolCheckItemCount)
                                            {
                                                bolRet = false;
                                                FileLogTrace.WriteErrorLog(string.Format(LogConst.LOG_ALIAS, targetAlias, migFolder.Name, MessageConst.MSG_ERROR_ITEMCOUNT));
                                            }
                                            else
                                            {
                                                clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_END, LogConst.LOG_COMPARE + subFolder.Name + LogConst.LOG_ITEMCOUNT));
                                            }
                                            if (subFolder.Items.Count != 0)
                                            {
                                                bool bolItemDateCompare = false;
                                                clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_START, LogConst.LOG_COMPARE + subFolder.Name + LogConst.LOG_SENDDATE));
                                                while (!bolItemDateCompare && intCheckCount <= 100)
                                                {
                                                    try
                                                    {
                                                        Thread.Sleep(100);
                                                        intCheckCount++;
                                                        Outlook.MailItem targetItem = copyFolder.Items.GetFirst();
                                                        Outlook.MailItem sourceItem = subFolder.Items.GetFirst();
                                                        if (targetItem.SentOn == sourceItem.SentOn)
                                                        {
                                                            targetItem = copyFolder.Items.GetLast();
                                                            sourceItem = subFolder.Items.GetLast();
                                                            if (targetItem.SentOn == sourceItem.SentOn)
                                                            {
                                                                bolItemDateCompare = true;
                                                                intCheckCount = 0;
                                                            }
                                                        }
                                                    }
                                                    catch
                                                    {
                                                        bolItemDateCompare = false;
                                                    }
                                                }
                                                if (!bolItemDateCompare)
                                                {
                                                    bolRet = false;
                                                    FileLogTrace.WriteErrorLog(string.Format(LogConst.LOG_ALIAS, targetAlias, migFolder.Name, MessageConst.MSG_ERROR_ITEMCOUNT));
                                                }
                                                else
                                                {
                                                    clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_END, LogConst.LOG_COMPARE + subFolder.Name + LogConst.LOG_SENDDATE));
                                                }
                                            }
                                            if (subFolder.Items.Count != 0)
                                            {
                                                if (!clsMod.SearchString(subFolder.Name, ApplicationConst.MEIWAKU_FOLDER))
                                                {
                                                    clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_START, LogConst.LOG_COMPARE + subFolder.Name + LogConst.LOG_ATTACHMENTCOUNT));
                                                    bool bolItemAttachmentCount = false;
                                                    while (!bolItemAttachmentCount && intCheckCount <= 100)
                                                    {
                                                        try
                                                        {
                                                            Thread.Sleep(100);
                                                            intCheckCount++;
                                                            Outlook.MailItem targetItem = copyFolder.Items.GetFirst();
                                                            Outlook.MailItem sourceItem = subFolder.Items.GetFirst();
                                                            if (targetItem.Attachments.Count == sourceItem.Attachments.Count)
                                                            {
                                                                bolItemAttachmentCount = true;
                                                                intCheckCount = 0;
                                                            }
                                                        }
                                                        catch
                                                        {
                                                            bolItemAttachmentCount = false;
                                                        }
                                                    }
                                                    if (!bolItemAttachmentCount)
                                                    {
                                                        bolRet = false;
                                                        FileLogTrace.WriteErrorLog(string.Format(LogConst.LOG_ALIAS, targetAlias, migFolder.Name, MessageConst.MSG_ERROR_ITEMCOUNT));
                                                    }
                                                    else
                                                    {
                                                        clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_END, LogConst.LOG_COMPARE + subFolder.Name + LogConst.LOG_ATTACHMENTCOUNT));
                                                    }
                                                }
                                            }
                                        }
                                        catch
                                        {
                                            bolRet = false;
                                        }
                                    }
                                }
                                if (intCheckCount >= 100)
                                {
                                    clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_NOT_MATCH, LogConst.LOG_COMPAREITEM));
                                    FileLogTrace.WriteErrorLog(string.Format(LogConst.LOG_ALIAS, targetAlias, migFolder.Name, MessageConst.MSG_ERROR_ITEMCOUNT));
                                    bolRet = false;
                                    continue;
                                }
                            }
                            long lngWaitTime = time * 1000;
                            if (File.Exists(strFilePath))
                            {
                                FileInfo f = new FileInfo(strFilePath);
                                if (f.Length > 100000000)
                                {
                                    long modTime = f.Length / 100000000;
                                    lngWaitTime = modTime * lngWaitTime + modTime * lngWaitTime;
                                }
                            }
                            clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_START, "移行用Pstファイル作成待機"));
                            int Count = 1;
                            Count = (int)lngWaitTime / 1000;
                            for (int i = 1; i <= Count; i++)
                            {
                                clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_INPROGRESS, "移行用Pstファイル作成待機"));
                                Thread.Sleep(1000);
                                System.Windows.Forms.Application.DoEvents();
                            }
                            clsMod.WriteLog(txtLog, string.Format(LogConst.LOG_END, "移行用Pstファイル作成待機"));
                            //プロファイルから新しいストアを削除
                            OutLookSession.RemoveStore(newRootFolder);
                            Marshal.ReleaseComObject(newRootFolder);
                            break;
                        }
                    }
                    break;
                }
            }
            return bolRet;
        }

        /// <summary>
        /// パブリックフォルダーデータを出力
        /// </summary>
        /// <param name="strFilePath">生成されるPSTファイルパス</param>
        /// <param name="publicFolderName">パブリックフォルダー名</param>
        public void ExportPublicFolderPstFile(string strFilePath, string publicFolderName)
        {
            Outlook.MAPIFolder publicFolder = null;
            try
            {
                publicFolder = OutLookSession.GetDefaultFolder(Outlook.OlDefaultFolders.olPublicFoldersAllPublicFolders);
                Thread.Sleep(3000);
                publicFolder = OutLookSession.GetDefaultFolder(Outlook.OlDefaultFolders.olPublicFoldersAllPublicFolders);
                //新規ストアを作成
                OutLookSession.AddStoreEx(strFilePath, Outlook.OlStoreType.olStoreUnicode);
                foreach (Outlook.Store store in OutLookSession.Stores)
                {
                    if (store.FilePath == strFilePath)
                    {
                        //ルートフォルダ取得
                        Outlook.MAPIFolder newRootFolder = store.GetRootFolder();
                        Outlook.MAPIFolder newSubFolder = null;
                        foreach (Outlook.MAPIFolder folder in newRootFolder.Folders)
                        {
                            if (folder.Name == publicFolderName)
                            {
                                folder.Delete();
                                break;
                            }
                        }
                        if (newSubFolder == null)
                        {
                            newSubFolder = newRootFolder.Folders.Add(publicFolderName);
                        }
                        //サブフォルダを新しいストアのフォルダにコピー
                        //（中のアイテムも一緒にコピーされる）
                        foreach (Outlook.MAPIFolder subFolder in publicFolder.Folders)
                        {
                            subFolder.CopyTo(newSubFolder);
                        }
                        //プロファイルから新しいストアを削除
                        OutLookSession.RemoveStore(newRootFolder);
                        Marshal.ReleaseComObject(newSubFolder);
                        Marshal.ReleaseComObject(newRootFolder);
                        break;
                    }
                }
            }
            catch(Exception ex)
            {
                Marshal.ReleaseComObject(publicFolder);
                throw ex;
            }
            //finally
            //{
            //    Marshal.ReleaseComObject(publicFolder);
            //}
        }

        /// <summary>
        /// パブリックフォルダーデータを取り込む
        /// </summary>
        /// <param name="strFilePath">生成されるPSTファイルパス</param>
        /// <param name="publicFolderName">パブリックフォルダー名</param>
        public void ImportPublicFolderPstFile(string strFilePath, string publicFolderName)
        {
            Outlook.MAPIFolder ex2013PublicFolder = null;
            try
            {
                //パブリックフォルダを取得する
                ex2013PublicFolder = OutLookSession.GetDefaultFolder(Outlook.OlDefaultFolders.olPublicFoldersAllPublicFolders);
                Thread.Sleep(3000);
                ex2013PublicFolder = OutLookSession.GetDefaultFolder(Outlook.OlDefaultFolders.olPublicFoldersAllPublicFolders);
                //Ex2003パブリックフォルダのPstファイル読み込む
                OutLookSession.AddStoreEx(strFilePath, Outlook.OlStoreType.olStoreUnicode);
                foreach (Outlook.Store store in OutLookSession.Stores)
                {
                    if (store.FilePath == strFilePath)
                    {
                        //Ex2003パブリックフォルダのルートフォルダ取得
                        Outlook.MAPIFolder ex2003PublicFolder = store.GetRootFolder();

                        foreach (Outlook.MAPIFolder subFolder in ex2003PublicFolder.Folders)
                        {
                            if (subFolder.Name == publicFolderName)
                            {
                                try
                                {
                                    subFolder.CopyTo(ex2013PublicFolder);
                                }
                                catch
                                {

                                }
                            }
                        }
                        //プロファイルから新しいストアを削除
                        OutLookSession.RemoveStore(ex2003PublicFolder);
                        Marshal.ReleaseComObject(ex2003PublicFolder);
                        break;
                    }
                }
            }
            catch(Exception ex)
            {
                Marshal.ReleaseComObject(ex2013PublicFolder);
                throw ex;
            }
            //finally
            //{
            //    Marshal.ReleaseComObject(ex2013PublicFolder);
            //}
        }
        #endregion
    }
}
